﻿

#ifndef __OS_CONFIGURE_INCLUDED_H_
#define __OS_CONFIGURE_INCLUDED_H_
////////////////////////////////////////////////////////////////////////////////
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
#pragma once
#endif
////////////////////////////////////////////////////////////////////////////////
#include <asio++/os.h>
////////////////////////////////////////////////////////////////////////////////
//Windows
////////////////////////////////////////////////////////////////////////////////
#if defined(OS_WINDOWS)
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif

#ifndef _WIN32_WINNT
#define _WIN32_WINNT 0x0501
#endif

#include <windows.h>
#include <algorithm>
#include <stdio.h>
#include <malloc.h>
#include <direct.h>
#include <mmsystem.h>

#pragma warning(disable: 4333)
#pragma warning(disable: 4003)
#pragma warning(disable: 4996)
#pragma comment(lib, "winmm.lib")

#ifndef begin_period
#define begin_period(n) ::timeBeginPeriod(n)
#endif

#ifndef end_period
#define end_period(n) ::timeEndPeriod(n)
#endif

inline bool make_dir(const char *path){
    HANDLE hfind;
    WIN32_FIND_DATAA data;
    hfind = FindFirstFileA(path, &data);

    if (hfind != INVALID_HANDLE_VALUE){
        FindClose(hfind);
        return true;
    }
    return (_mkdir(path) == 0);
}
inline const char* get_run_path(char *path, int count){
    char filename[MAX_PATH] = {0};
    GetModuleFileNameA(NULL, filename, MAX_PATH);
    char *pos = strrchr(filename, '\\');
    if (!pos){
        return 0;
    }
    *pos = 0;
    if ((int)strlen(filename) + 1 > count)
        return 0;
    return (strcpy(path, filename), path);
}
inline const std::string& get_run_path()
{
    static std::string cur_path;
    if (!cur_path.empty())
        return cur_path;

    char filepath[MAX_PATH] = {0};
    cur_path = get_run_path(filepath, MAX_PATH) ? filepath : ".\\";
    return cur_path;
}
inline unsigned int time_get_time(){
    return timeGetTime();
}
////////////////////////////////////////////////////////////////////////////////
//Apple or iOS
////////////////////////////////////////////////////////////////////////////////
#elif defined(OS_APPLE)
#include <algorithm>
#include <strings.h>
#include <mm_malloc.h>
#include <unistd.h>
#include <dirent.h>
#include <linux/kernel.h>

typedef long long __int64;

#ifndef _stricmp
#define _stricmp strcasecmp
#endif

#ifndef begin_period
#define begin_period(n) void(0)
#endif

#ifndef end_period
#define end_period(n) void(0)
#endif

inline bool make_dir(const char *path){
    DIR *dir = opendir(path);
    if (dir != 0){
        closedir(dir);
        return true;
    }
    mode_t mode = S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH;
    return (mkdir(path, mode) == 0);
}
inline int _chdir(const char *path){
    return chdir(path);
}
inline const char* get_run_path(char *path, int count){
    int i;
    int rslt = readlink("/proc/self/exe", path, count - 1);
    if (rslt < 0 || (rslt >= count - 1))
        return 0;

    path[rslt] = '\0';
    for (i = rslt; i >= 0; i--){
        if (path[i] == '/'){
            path[i + 1] = '\0';
            break;
        }
    }
    return path;
}
inline const std::string& get_run_path(){
    static std::string cur_path;
    if (!cur_path.empty())
        return cur_path;

    char filepath[1024] = {0};
    cur_path = get_run_path(filepath, 1024) ? filepath : "./";
    return cur_path;
}
inline unsigned int time_get_time(){
    struct timespec ts;
    clock_serv_t cclock;
    mach_timespec_t mts;
    host_get_clock_service(mach_host_self(), CALENDAR_CLOCK, &cclock);
    clock_get_time(cclock, &mts);
    mach_port_deallocate(mach_task_self(), cclock);
    ts.tv_sec  = mts.tv_sec;
    ts.tv_nsec = mts.tv_nsec;
    return (unsigned int)(ts.tv_sec * 1000 + ts.tv_nsec / 1000000);
}
inline int _vscprintf(const char *format, va_list pargs){
    int retval; 
    va_list argcopy;
    va_copy(argcopy, pargs); 
    retval = vsnprintf(0, 0, format, argcopy); 
    va_end(argcopy); 
    return retval;
}
////////////////////////////////////////////////////////////////////////////////
//Linux other
////////////////////////////////////////////////////////////////////////////////
#else
#include <algorithm>
#include <strings.h>
#include <malloc.h>
#include <unistd.h>
#include <dirent.h>
#include <linux/kernel.h>

typedef long long __int64;

#ifndef _stricmp
#define _stricmp strcasecmp
#endif

#ifndef begin_period
#define begin_period(n) void(0)
#endif

#ifndef end_period
#define end_period(n) void(0)
#endif

inline bool make_dir(const char *path){
    DIR *dir = opendir(path);
    if (dir != 0){
        closedir(dir);
        return true;
    }
    mode_t mode = S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH;
    return (mkdir(path, mode) == 0);
}
inline int _chdir(const char *path){
    return chdir(path);
}
inline const char* get_run_path(char *path, int count){
    int i;
    int rslt = readlink("/proc/self/exe", path, count - 1);
    if (rslt < 0 || (rslt >= count - 1))
        return 0;

    path[rslt] = '\0';
    for (i = rslt; i >= 0; i--){
        if (path[i] == '/'){
            path[i + 1] = '\0';
            break;
        }
    }
    return path;
}
inline const std::string& get_run_path(){
    static std::string cur_path;
    if (!cur_path.empty())
        return cur_path;

    char filepath[1024] = {0};
    cur_path = get_run_path(filepath, 1024) ? filepath : "./";
    return cur_path;
}
inline unsigned int time_get_time(){
    struct timespec ts;
    clock_gettime(CLOCK_MONOTONIC, &ts);
    return (unsigned int)(ts.tv_sec * 1000 + ts.tv_nsec / 1000000);
}
inline int _vscprintf(const char *format, va_list pargs){
    int retval; 
    va_list argcopy;
    va_copy(argcopy, pargs); 
    retval = vsnprintf(0, 0, format, argcopy); 
    va_end(argcopy); 
    return retval;
}
#endif
////////////////////////////////////////////////////////////////////////////////
#ifndef NULL
#define NULL 0
#endif
////////////////////////////////////////////////////////////////////////////////
#ifndef INFINITE
#define INFINITE (~0)
#endif
////////////////////////////////////////////////////////////////////////////////
#endif //__OS_CONFIGURE_INCLUDED_H_
